#ifndef __RED_ARRAY_OBJECT_H__
#define __RED_ARRAY_OBJECT_H__

#include "thread.h"
#include "redobject.h"
#include "redexceptionobject.h"

#define RED_ARRAY_INIT_SIZE		512

typedef struct _RedArrayObject
{
	RedObject_HEAD

	int			  ar_nmods;
	RedObject	**ar_items;
	RedMutex	  ar_mutex;
	int			  ar_length;
	int			  ar_capacity;
} RedArrayObject;

RED_EXPORT extern RedTypeObject RedType_Array;

#define RedArray_Exact(o)			((o)->ob_type == &RedType_Array)
#define RedArray_NMods(o)			(((RedArrayObject *)(o))->ar_nmods)
#define RedArray_Items(o)			(((RedArrayObject *)(o))->ar_items)
#define RedArray_Length(o)			(((RedArrayObject *)(o))->ar_length)
#define RedArray_Capacity(o)		(((RedArrayObject *)(o))->ar_capacity)

#define RedArray_Mutex(o)			(&(((RedArrayObject *)(o))->ar_mutex))
#define RedArray_Unlock(o)			RedMutex_Release(RedArray_Mutex(o))
#define RedArray_ReadLock(o, m)					\
	do											\
	{											\
		RedMutex_Acquire(RedArray_Mutex(o));	\
		(m) = RedArray_NMods(o);				\
	} while (0)

#define RedArray_WriteLock(o, m)				\
	do											\
	{											\
		RedMutex_Acquire(RedArray_Mutex(o));	\
		(m) = ATOMIC_INC(RedArray_NMods(o));	\
	} while (0)

#define RedArray_CheckMods(o, m)				\
	({											\
		char _ok = (RedArray_NMods(o) == (m));	\
		if (!_ok)								\
		{										\
			RedArray_Unlock(o);					\
			RedException_ThrowFormat(			\
				&RedExc_RuntimeError,			\
				"Modified during operation");	\
		}										\
		_ok;									\
	})

RED_EXPORT RedObject *RedArray_Create(void);
RED_EXPORT RedObject *RedArray_CreatePresized(int size);

RED_EXPORT char RedArray_Sort(RedObject *self, RedObject *cmp);
RED_EXPORT char RedArray_Clear(RedObject *self);
RED_EXPORT char RedArray_Append(RedObject *self, RedObject *item);
RED_EXPORT char RedArray_Remove(RedObject *self, RedObject *item);
RED_EXPORT char RedArray_Extend(RedObject *self, RedObject *array);
RED_EXPORT char RedArray_Insert(RedObject *self, RedObject *item, int index);

RED_EXPORT RedObject *RedArray_Pop(RedObject *self);
RED_EXPORT RedObject *RedArray_Copy(RedObject *self);
RED_EXPORT RedObject *RedArray_Concat(RedObject *self, RedObject *array);

RED_EXPORT RedObject *RedArray_DelItem(RedObject *self, RedObject *index);
RED_EXPORT RedObject *RedArray_GetItem(RedObject *self, RedObject *index);
RED_EXPORT RedObject *RedArray_SetItem(RedObject *self, RedObject *index, RedObject *item);

#endif /* __RED_ARRAY_OBJECT_H__ */
